package com.itheima.service.impl;


import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.constant.MessageConstant;
import com.itheima.dao.MemberDao;
import com.itheima.dao.OrderDao;
import com.itheima.dao.OrderSettingDao;
import com.itheima.dao.SetmealDao;
import com.itheima.entity.PageResult;
import com.itheima.entity.QueryPageBean;
import com.itheima.entity.Result;
import com.itheima.exception.*;
import com.itheima.pojo.Member;
import com.itheima.pojo.Order;
import com.itheima.pojo.OrderSetting;
import com.itheima.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.JedisPool;


import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service(interfaceClass = OrderService.class)

public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderSettingDao orderSettingDao;
    @Autowired
    private MemberDao memberDao;
    @Autowired
    private SetmealDao setmealDao;
    @Autowired
    private OrderDao orderDao;

    @Autowired
    private JedisPool jedisPool;


    @Override
    @Transactional
    //预约一个套餐
    public void order(Map map) throws ParseException, OrderDateNullException, OrderNotAllowedException, OrderFullException, OrderRepeatedException {

        Integer setmealId = Integer.parseInt((String) map.get("setmealId"));
        //查询出此套餐的名称
        String setmealName = setmealDao.findNameById(setmealId);

        //1.判断预约的日期是否进行过预约设置，即确定当天是否可预约
        String orderDate = (String) map.get("orderDate");
        System.out.println(orderDate);
        if (orderDate == null){
            throw new OrderDateNullException();
            //return new Result(false,"预约日期不能为空");
        }

        Date date = new SimpleDateFormat("yyyy-MM-dd").parse(orderDate);

        //因为后续要判断是否预约满，就需要取其中的数据，所以重新构造一个方法
        OrderSetting orderSetting = orderSettingDao.findOrderSettingByDate(date);
        if(orderSetting == null){
            //当天没进行预约设置，不可预约
            throw new OrderNotAllowedException();
            //return new Result(false, MessageConstant.SELECTED_DATE_CANNOT_ORDER);
        }

        //2.判断当天是否已经预约满了
        if(orderSetting.getReservations() >= orderSetting.getNumber()){
            //如果预约数大于等于可预约数，预约已满，不能预约
            throw new OrderFullException();
            //return new Result(false,MessageConstant.ORDER_FULL);
        }

        //3.判断是否重复预约
        String phoneNumber = (String) map.get("phoneNumber");

        //根据手机号，获取member_id
        Member member = memberDao.findByTelephone(phoneNumber);

        //4.判断当前手机号是否存在于member表中，即是否为成为用户
        //如果没有成员用户，就自动成为用户
        if(member != null){
            //如果是此手机号已成为用户
            Integer memberId = member.getId();
            //根据用户的id，预约日期，套餐id从order表中判断是否重复预约
            Order order = new Order();
            order.setMemberId(memberId);
            order.setOrderDate(date);
            order.setSetmealId(setmealId);
            List<Order> orderList = orderDao.findByCondition(order);
            if(orderList != null && orderList.size() >0){
                //说明，当前用户，当前日期，当前套餐已经预约过
                throw new OrderRepeatedException(setmealName);
                //return new Result(false,setmealName+MessageConstant.HAS_ORDERED);
            }
        }else{
            //如果此手机号没有成为用户，就不会存在重复预约的情况
            //只需要自动给这个手机号码加入到用户
            //如果能走到这，说名member为null，重新赋值
            member = new Member();
            String name = (String) map.get("name");
            String sex = (String) map.get("sex");
            String idCard = (String) map.get("idCard");
            Object birthDay = map.get("birthDay");
            if(birthDay != null){
                Date birth = new SimpleDateFormat("yyyy-MM-dd").parse((String) birthDay);
                member.setBirthday(birth);
            }
            member.setPhoneNumber(phoneNumber);
            member.setName(name);
            member.setSex(sex);
            member.setIdCard(idCard);
            member.setRegTime(new Date());

            memberDao.add(member);
        }

        //5.此时才真正预约，在order中插入该条数据
        Order order = new Order();
        order.setMemberId(member.getId());
        order.setOrderDate(date);
        order.setOrderType((String)map.get("orderType"));
        order.setOrderStatus((String) map.get("orderStatus"));
        order.setSetmealId(setmealId);
        orderDao.add(order);

        //更新预约设置表中的预约数
        int reservations = orderSetting.getReservations() + 1;
        orderSetting.setReservations(reservations);
        orderSettingDao.updateReservationsByOrderDate(orderSetting);

        //return new Result(true,setmealName+MessageConstant.ORDER_SUCCESS,order.getId());
    }

    @Override
    @Transactional
    //预约多个套餐(实现事务管理)
    public void orderMany(Map map, String[] setmealIds) throws OrderFullException, OrderDateNullException, OrderNotAllowedException, OrderRepeatedException {

        //遍历setmealIds
        for (String setmealId : setmealIds) {

            //存入此次预约的哪个套餐
            map.put("setmealId",setmealId);
            //设置预约方式为电话预约
            map.put("orderType", Order.ORDERTYPE_TELEPHONE);
            map.put("orderStatus",Order.ORDERSTATUS_NO);
            //调用order方法，一次预约一个套餐

            try {
                order(map);
            } catch (ParseException e) {
                e.printStackTrace();
            }catch (Exception e){
                throw e;
            }
        }
        //return new Result(true,MessageConstant.ORDER_SUCCESS);
    }


    @Override
    public Map findById(Integer orderId) {
        Map map = orderDao.findById4Detail(orderId);
        //此时查询数据库中的日期为date类型数据，发送前台需要转为成2020-3-23类型
        if(map != null){
            Date orderDate = (Date) map.get("orderDate");
            String date = new SimpleDateFormat("yyyy-MM-dd").format(orderDate);
            map.put("orderDate",date);
        }
        return map;
    }

    @Override
    public PageResult findPage(QueryPageBean queryPageBean) {
        //出去前台传过来的数据
        Integer currentPage = queryPageBean.getCurrentPage();
        Integer pageSize = queryPageBean.getPageSize();
        String queryString = queryPageBean.getQueryString();

        /*
        * 加一个优化，每次查询条件变换时，就查询第一页
        * 每次查询时就判断查询条件是否变更(查询的时候把查询条件存入redis中，然后再取)
        * */
        //获取redis中存放的查询条件
        String queryString4OrderList = jedisPool.getResource().get("queryString4OrderList");

        //如果时第一次查询，就给一个空条件的默认值,存入redis中
        if(queryString4OrderList == null){
            jedisPool.getResource().set("queryString4OrderList","empty condition");
            queryString4OrderList = "emptyCondition";
        }

        //如果查询条件变更了
        if(queryString == null){
            //如果查询条件为空，就给他赋值为默认值
            queryString = "emptyCondition";
        }

        //查询条件变更,就查询第一页
        if(!queryString4OrderList.equals(queryString)){
            jedisPool.getResource().set("queryString4OrderList",queryString);
            currentPage = 1;
        }

        //此时使用pageHelper
        System.out.println("此次查询的是第"+currentPage+"页");
        PageHelper.startPage(currentPage,pageSize);

        //说明此次查询的条件为空
        if("emptyCondition".equals(queryString)){
            queryString = null;
        }

        Page<Map<String,Object>> page = orderDao.findPage(queryString);
        List<Map<String, Object>> list = page.getResult();
        //由于数据库中查询出来的数据是date格式，显示为2020-4-5 00：00：00
        //将其转化为string格式 2020-4-5

        if(list != null && list.size()>0){
            //遍历list集合（此时再for中需要修改list中的数据）
            for (int i = 0; i < list.size(); i++) {
                Map<String, Object> map = list.get(i);
                Date orderDate = (Date) map.get("orderDate");
                String date = new SimpleDateFormat("yyyy-MM-dd").format(orderDate);
                map.put("orderDate",date);
            }
        }

        return new PageResult(page.getTotal(),page.getResult());
    }




    @Override
    @Transactional
    //确认到诊方法
    public Result confirmById(Integer id) {
        //确认到诊之前，需要判断预约日期是否为今天
        //根据预约id查询当前预约的orderDate
        Order order = orderDao.findById(id);
        Date orderDate = order.getOrderDate();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String orderDay = sdf.format(orderDate);
        String today = sdf.format(new Date());
        //判断预约日期是否是今天
        if(today.equals(orderDay)){
            order.setOrderStatus(Order.ORDERSTATUS_YES);
            orderDao.updateOrderStatus(order);
            return new Result(true,MessageConstant.CONFIRM_ORDER_SUCCESS);
        }
        return new Result(false,MessageConstant.CONFIRM_ORDER_DISABLED);
    }


    @Override
    @Transactional
    //取消预约方法(单个预约)
    public void cancelById(Integer id) throws OrderDisabledException {
        //删除之前，先判断此预约是否已过期
        //根据id查询此预约
        Order order = orderDao.findById(id);
        Date orderDate = order.getOrderDate();

        //获取今天0时0分0秒的date
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date today = sdf.parse(sdf.format(new Date()));
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //判断预约时间是否在今天之前(要和今天的0时0分0秒比较)
        if(orderDate.before(new Date())){
            //提示，预约已过期，不能删除(留档记录)
            //此时今天不小于今天，就可以删除,
            /*
            如果当前预约不能取消，那我就手动抛出自定义异常，此时取消预约方法会回滚
            在cancelByIds方法中，直接调用此方法，然后捕获此自定义异常
            如果捕获到了此自定义异常，就说明当前预约取消失败，再手动抛异常
            那么cancelByIds方法中出现异常，就会回滚，这样就实现了
            批量取消就实现了事务管理(一个取消失败，所有的取消都不成功)
            */
            Map orderDetail = orderDao.findById4Detail(id);
            String setmealName = (String) orderDetail.get("setmeal");

            throw new OrderDisabledException(setmealName);
            //return new Result(false,id + MessageConstant.CANCEL_ORDER_DISABLED);
        }
        //如果未过期，删除id对应的预约，
        orderDao.deleteById(id);

        //获取到此预约日期当天的已预约数量
        OrderSetting orderSetting = orderSettingDao.findOrderSettingByDate(orderDate);
        //将当天的已预约数减一
        int reservations = orderSetting.getReservations() - 1;
        orderSetting.setReservations(reservations);
        orderSettingDao.updateReservationsByOrderDate(orderSetting);

        //return new Result(true,id + MessageConstant.CANCEL_ORDER_SUCCESS);
    }

    @Override
    @Transactional
    //批量取消(实现了事务管理)
    public void cancelByIds(Integer[] orderIds) throws OrderDisabledException {
        //遍历预约id
        for (Integer orderId : orderIds) {
            try {
                cancelById(orderId);
                //如果当前预约取消失败，此处会捕获到自定义异常
            } catch (OrderDisabledException e) {
                //捕获到异常，继续往上抛，这样此方法就会回滚
                throw e;
            }
        }
    }

}
